本文为您详细介绍呼叫中心SDK前端接入流程。

在线体验

如果您已经有SaaS工作台的账号,您可以在线体验,并且完全可以按照这个Demo的方式进行接入。

接入热线SDK

所有使用${version}的地方,需要替换为真实的版本号。详细记录信息,请参见热线SDK更新记录

  • 使用非定制UI接入
    • 如果您不需要定制自己的UI,并且您是React体系的项目接入,只需添加以下CDN的资源:
      <link rel="stylesheet" href="//at.alicdn.com/t/font_1263869_rz6l63j0yrp.css"/>
      <link rel="stylesheet" href="//g.alicdn.com/code/lib/antd/4.x.x/antd.min.css"/>
      <link rel="stylesheet" href="//g.alicdn.com/hotline-client/hotline-client-sdk/${version}/hotline-client-ui/index.css"/>
      <script src="//g.alicdn.com/code/lib/antd/4.x.x/antd.min.js"></script>
      <script src="//g.alicdn.com/hotline-client/hotline-client-sdk/${version}/hotline-client-ui/index.js"></script>
      注意 请确保您的项目中已经有React、ReactDOM、antd的CDN资源,其中antd的版本建议使用4.x系列。
    • 因为构建出的是标准的UMD资源,所以现在可以按照以下方式接入:
      window.HotlineClientUi.renderClient(
          domContainer, //  比如 document.querySelector('#root'),可以替换为任何你想插入的DOM节点。
          props,
      );
    • 如果您使用了webpack,还可以使用以下方式接入:
      // webpack.config.js
      module.exports = {
        //...
        externals: {
          HotlineClient: 'HotlineClientUi'
        }
      };
      
      // in your app or component
      import { HotlineClientUI } from 'HotlineClient';
      window.HotlineClientUi.renderClient(
          domContainer, //  比如 document.querySelector('#root'),可以替换为任何你想插入的DOM节点。
          props,
      )

    上述所有入参的props的内容,请参见HotlineClientUIProps。

  • 使用定制UI接入

    如果您需要定制自己的UI风格,或者需要定制其他UI框架下的组件(比如VUE),可以按照下面的方式来实现:

    1. 引入以下资源:
      <script src="//g.alicdn.com/hotline-client/hotline-client-sdk/${version}/hotline-client-fuyun/index.js"></script>
    2. 在自己的代码中创建一个HotlineClient的实例:
      const { FuYunHotlineClient } = window.HotlineClientFuyun;
      
      const client = new FuYunHotlineClient(config);
    3. 如果您是React体系的项目但是需要定制UI,我们也提供了hooks供您使用:
      // 需要在cdn中添加 <script src="//g.alicdn.com/hotline-client/hotline-client-sdk/${version}/hotline-client-ui/index.js"></script>
      const { useClient } = window.HotlineClientUi;
      const {
        client,           // HotlineClient  实例
        enableState,      // EnableState 使能状态
        agentContext,     // AgentContext
        callContext,      // CallContext 
        checkIn,          // 上班签入,可以直接调用
        handleAnswerCall, // 接电话
        handleDial,       // 拨电话
      } = useClient(props);

    其中props的内容请参考HotlineClientUIProps介绍,EnableState内容请参考EnableState。

  • 不需要UI接入
    如果您不需要UI,直接使用API的形式调用,我们也提供了一个扁平化API的版本,只需要引入下面这个CDN地址:
    <script src="//g.alicdn.com/hotline-client/hotline-client-sdk/${version}/hotline-client-api/index.js"></script>
    使用方式:
    const getHotlineClientSDK = window.HotlineClientApi.default;
    
    // config: HotlineClientInitConfig
    const SDK = getHotlineClientSDK(config);
    
    console.log(SDK.client); // 获取client。
    
    console.log(SDK.agent); // 获取agent。
    
    onsole.log(SDK.call); // 获取call。
    
    console.log(SDK.enableState); //获取使能状态。
    
    // 上班签入。
    SDK.agentCheckin();
    
    //  下班签出。
    SDK.agentCheckout();
    
    // 切空闲。
    SDK.agentCheckReady();
    
    // 切小休。
    SDK.agentCheckRestful();
    
    //外呼。
    SDK.dial(calleePhoneNumber: string, callerPhoneNumber?: string);
    
    // 接电话
    SDK.answer();
    
    // 电话保持。
    SDK.hold();
    
    // 电话取回。
    SDK.retrieve();
    
    // 电话转交。
    SDK.deflect(identifier: DeflectionIdentifier);
    
    // 电话挂断。
    SDK.hangUp();
    
    // 释放资源。
    SDK.dispose();
    因为状态机是维护在后端的,除了由于没有client、agent或者call导致的报错外(比如没有通话直接调挂断),其余的动作都需要用户根据enableState当前的状态判断是否可以发起,比如发起外呼:1当前如果外呼是否可以发起,API本身不会拦截,应该由状态进行拦截。

SDK接入常见问题

  • 怎么订阅事件?
    热线中基本上每一个动作(比如状态切换、电话状态变更等)都会对应一些事件,为了保证所有后端的事件都完整的传递给上层应用,我们在HotlineClient的实例上提供了完整的事件监听功能,您可以按照这样的方式从client上发起监听:
    client.on('eventName', (data: EventData) => {})

    其中eventName可以是HotlineSystemEvents和HotlineCustomEvents中任意的一个key,正如命名所指,HotlineSystemEvents推送的都是后端直接给到的事件信息,而HotlineCustomEvents是SDK系统中自己触发的事件。

    目前所有的EventData都是HotlineSocketEventData。

  • 使用过程中会不会有环境问题?

    会的,目前我们只支持Chrome浏览器64版本以上的环境,我们提供了完整的环境检测工具,包括网络检测、麦克风检测和远端音频播放流程检测。

  • 以UI形式接入环境检测工具
    首先,一定需要以带UI的形式使用,然后加入下面的2个CDN:
    <link rel="stylesheet" href="//g.alicdn.com/hotline-client/hotline-client-sdk/1.0.1/hotline-client-check-tools/index.css"/>
    <script src="//g.alicdn.com/hotline-client/hotline-client-sdk/1.0.1/hotline-client-check-tools/index.js"></script>
    现在你只需要将openCheckTool设置为true即可。
  • 是否可以用npm的形式接入?

    考虑到一些依赖需要单独处理的问题,建议使用CDN的形式接入。

术语表

术语详细说明,请参见下表:
术语 说明
Client 即HotlineClient的实例,可以通过create的方式获取,如果直接以UI形式接入,可以通过onClientOnline回调的方式获取。
Agent 即AgentContext的实例,client调用login之后可以拿到,如果以UI形式接入,可以通过onAgentOnline回调的方式获取。
Call 即CallContext的实例,agent调用dial(外呼)或者振铃的时候,可以从几个特殊事件中可以获取到。
  • 系统外呼事件
    外呼事件触发的时候会有callContext:
    client.on('SystemCallDialOut', (dialOutCallContext) => {console.log(dialOutCallContext)})
  • 系统振铃事件
    系统振铃事件触发会有callContext:
    client.on('SystemCallRinging',(ringingCallContext) => {console.log(ringingCallContext) });
  • 断线重连(用户主动刷新浏览器)事件
    系统断线重连事件触发会有CallContext:
    // status 当前断线重连的状态。
    client.on('AgentCallReconnect',(status, callContext) => {console.log(status, callContext) });
EnableState 状态使能类表示在当前的坐席状态下是否允许一些操作的使用,比如在一通话务中,是否可以挂断,是否可以转接等等完全由这个“使能类”来定义,类型定义,请参见:HotlineClientEnableState。

类型定义

  • Client相关
    • HotlineClient
      interface HotlineClient {
        /**
         * 获取此热线客户端的上下文对象。
         */
        readonly context: HotlineClientContext;
      
        /**
         * 发起登录。
         *
         * {@return 一个坐席上下文对象}。
         */
        login(): Promise<AgentContext>;
        /**
         * 更新token。
         */
        updateToken(token: string): void;
      }
    • FuYunHotlineClient
      class FuYunHotlineClient implements HotlineClient {
          /**
         * ...
         */
      }
    • HotlineClientContext
      /**
       * 表示热线 client 的上下文对象
       */
      export interface HotlineClientContext {
        /**
         * 获取此 client 上的配置信息。
         */
        readonly config: HotlineClientInitConfig;
      
        /**
         * 获取此 client 上的热线服务。
         */
        readonly hotlineService: HotlineService;
      }
    • HotlineClientInitConfig
      /**
       * 提供 {@link HotlineClient} 初始化参数的描述。
       */
      export interface HotlineClientInitConfig {
        instanceId: string; // 实例 id
        token: string; // token
      }
    • HotlineClientUIProps
      /**
       * HotlineClientUIProps 定义。
       */
      export type HotlineClientUIProps = {
        /**
         * 初始化 Client 需要的参数。
         */
        config?: HotlineClientInitConfig;
      
        /**
         * 是否支持拖拽。默认为 false。
         */
        draggable?: boolean;
      
        /**
         * 拖拽相关的配置。具体可以参考 https://www.n****.com/package/react-draggable 
         * 的 DraggableProps
         */
        draggableProps?: Partial<DraggableProps>;
      
        /**
         * 是否打开检测工具。默认是关闭的。
         */
        openCheckTool?: boolean;
      
        /**
         * 电话号码是否加密,(脱敏),默认是 false。
         */
        isPhoneNumberEncrypted?: boolean;
      
        onClientOnline?: (client: HotlineClient) => void;
      
        onAgentOnline?: (agent: AgentContext) => void;
      
        onCallContextChange?: (callContext: CallContext) => void;
      
        onLoginError?: (error: Error) => void;
      };
    • HotlineClientEnableState
      export interface HotlineClientEnableState {
        /**
         * 状态。
         */
        status: AgentStatus;
      
        /**
         * 可签出。
         */
        checkoutEnable: boolean;
      
        /**
         * 可签入。
         */
        checkinEnable: boolean;
      
        /**
         * 可空闲。(继续工作)
         */
        readyEnable: boolean;
      
        /**
         * 可小休。
         */
        breakEnable: boolean;
      
        /**
         * 可培训。
         */
        trainEnable: boolean;
      
        /**
         * 可接电话。
         */
        callAnswerEnable: boolean;
      
        /**
         * 可挂电话。
         */
        callHangupEnable: boolean;
      
        /**
         * 可拨号。
         */
        callDialEnable: boolean;
      
        /**
         * 电话可保持。
         */
        callHoldEnable: boolean;
      
        /**
         * 电话可取回。
         *
         * 保持 + 转接。
         */
        callRetrieveEnable: boolean;
      
        /**
         * 电话可转接。
         */
        callDeflectEnable: boolean;
      }
  • Agent相关
    AgentContext
    /**
     * 表示坐席的接口定义。
     */
    export interface AgentContext extends Disposable {
      /**
       * 坐席发起签入。
       */
      checkIn(): Promise<unknown>;
    
      /**
       * 坐席发起签出。
       */
      checkOut(): Promise<unknown>;
    
      /**
       * 坐席发起小休。
       */
      doRest(): Promise<unknown>;
    
      /**
       * 坐席切到在线。
       */
      checkReady(): Promise<unknown>;
    
      /**
       * 坐席发起拨号。
       * @param calleePhoneNumber 被叫号码。
       * @param callerPhoneNumber 主叫号码。
       */
      dial(calleePhoneNumber: string, callerPhoneNumber?: string): Promise<CallContext>;
    
      /**
       * 坐席接电话。
       * @param params 接电话需要的身份信息。
       */
      answer(params?: CallIdentity): Promise<unknow>;
    }
  • Call相关
    • CallContext
      /**
       * 表示通话上下文的结构体。
       */
      export interface CallContext extends EventEmitter<HotlineConnectionEvents>, Disposable {
        /**
         * 获取此通话的标识信息。
         */
        readonly identity: CallIdentity;
      
        /**
         * 获取此通话的方向。
         */
        readonly callDirection: CallDirection;
      
        /**
         * 获取此通话的呼叫方身份。
         */
        readonly caller: CallerIdentity;
      
        /**
         * 获取此通话的被呼叫方身份。
         */
        readonly callee: CallerIdentity;
      
        /**
         * 挂断此通话。
         */
        hangUp(): Promise<unknown>;
      
        /**
         * 转接此通话。
         * @param identifier 转接需要的标识符。
         *
         * 根据 DeflectionIdentifier 的 deflectionType 来确认是否需要返回一个可取回的通话。
         */
        deflect(identifier: DeflectionIdentifier): void;
      
        /**
         * 保持此通话。
         */
        hold(): Promise<unknown>;
      
        /**
         * 表示取回此通话。
         */
        retrieve(): Promise<unknown>;
      }
    • CallIdentity
      /**
       * 表示通话身份的结构体。
       */
      export interface CallIdentity {
        /**
         * 获取此通话的 acId。
         */
        readonly acId: string;
      
        /**
         * 获取此通话的连接 Id。
         */
        readonly connId: string;
      
        /**
         * 获取此通话被保持时的连接 Id。
         */
        readonly holdConnId?: string;
      
        /**
         * 获取此通话的 jobId。
         */
        readonly jobId: string;
      }
    • CallDirection
      /**
       * 表示通话方向的枚举,如呼入或呼出。
       */
      export enum CallDirection {
        /**
         * 表示呼入。
         */
        Incoming,
      
        /**
         * 表示呼出。
         */
        Outgoing,
      }
  • Event事件相关
    • HotlineSystemEvents
      /**
       * 后端推送的事件。
       */
      export interface HotlineSystemEvents<EventData> {
        AgentCheckin: (data: EventData) => void; // 坐席签入
        AgentReady: (data: EventData) => void; // 坐席进入空闲(在线)状态
        AgentCallDialOut: (data: EventData) => void; // 坐席正在外呼事件
        AgentJoinChannel: (data: EventData) => void; // RTC 建立,坐席加入聊天
        AgentLeaveChannel: (data: EventData) => void; // RTC 断开,坐席离开聊天
        AgentCheckout: (data: EventData) => void; // 坐席签出事件
        AgentBreak: (data: EventData) => void; // 坐席小休事件
        AgentAcw: (data: EventData) => void; // 坐席进入话后处理事件
        AgentRinging: (data: EventData) => void; // 坐席振铃
        // AgentCallRelease: (data: EventData) => void; // 通话结束,商业化场景暂时没有
        AgentCallAnswerRequest: (data: EventData) => void; // FIXME: 待确认
        AgentCallInboundEstablish: (data: EventData) => void; // 入呼通道建立事件
        AgentCallOutBoundEstablish: (data: EventData) => void; // 外呼通道建立事件
        AgentCallConferenceWaitAnswer: (data: EventData) => void; // 双步转等待第三方接听事件
        AgentCallHeld: (data: EventData) => void; // 通话保持事件
      }
    • HotlineCustomEvents
      export interface HotlineCustomEvents<EventData> {  
      AgentStatusChange: (data: EventData) => void;               // 坐席状态变更事件  
      EnableStateChange: (data: HotlineClientEnableState) => void;// 使能类变更事件。  
      CallVoiceText: (data: EventData) => void;                   // 通话语音文本事件  
      AgentReconnect: (status: AgentStatus) => void;              // 坐席断线重连消息。  
      AgentCallReconnect: (status: AgentStatus, callContext: CallContext) => void; // 通话断线重连消息。  
      BeforeCallHold: () => void;                                 // 电话保持动作被触发前触发。  
      AfterCallHold: () => void;                                  // 电话保持成功后触发。  
      BeforeCallDeflect: () => void;                              // 电话转交动作被触发前触发。  
      BeforeCallHangup: () => void;                               // 电话挂断动作被触发前触发。  
      AfterCallHangup: () => void;                                // 电话挂断成功后触发。  
      BeforeCallAnswer: () => void;                               // 电话接起动作被触发前触发。  
      AfterCallAnswer: () => void;                                // 电话接起成功后触发。  
      BeforeCallDial: () => void;                                 // 电话拨号动作被触发前触发。  
      AfterCallDial: () => void;                                  // 电话拨号成功后触发。  
      BeforeCallRetrieve: () => void;                             // 电话取回动作被触发前触发。  
      AfterCallRetrieve: () => void;                              // 电话取回成功后触发。  
      UnHandleEvent: (data: EventData) => void;                   // 异常兜底。
      TokenExpired: () => void;                                   // Token过期事件。  
      SystemCallRinging: (call: CallContext) => void;             // 带话务上下文的系统振铃事件。  
      SystemCallDialOut: (call: CallContext) => void;             // 带话务上下文的系统外呼事件。
      }
    • HotlineSocketEventData
      /**
       * 热线 socket 消息体
       */
      export interface HotlineSocketEventData {
        eventName: string;
        buId?: number;
        departmentId?: number;
        enumIconType?: string;
        enumSceneType?: string;
        gmtCreate?: number;
        head: HotlineSocketHeadData;
        isPersistent?: boolean;
        sceneType?: string;
        senderId?: number;
        senderType?: string;
        userId?: number;
        uuid?: string;
        content: string;
      }
      
      export interface HotlineSocketHeadData {
        agentBasicCode?: AgentBasicCode;
        agentBasicDesc?: string;
        agentCallCode?: AgentCallCode;
        agentCallDesc?: string;
        aid?: string;
        appName?: string;
        cmd?: string;
        departmentId?: string;
        mid?: string;
        name?: string;
        supportNewFunction?: string;
        time?: string;
        tk?: string;
        xspaceHotline?: string;
        jobId?: string;
        connId?: string;
        holdConnId?: string;
        acid?: string;
        dnis?: string;
        ani?: string;
      }
  • 其他类型说明
    DeflectionIdentifier
    export interface DeflectionIdentifier {
      isSingleTransfer?: boolean; // true 是单步转,false 是双步转,默认是 true
      isTransferSkillGroup?: boolean; // 是否转接给技能组。
      isTransferPhone?: boolean; // 是否转接给电话号。
      caller?: string; // 转接到电话的主叫号码。
      callee?: string; // 转接到电话的被叫号码。
      skillGroupId?: string; // 转接的技能组 id
    }